import time
from collections import OrderedDict
from threading import Lock
from typing import Optional, Dict, Any

# 从utils模块导入MySQL查询函数
from utils import query_mysql

# 元数据解析缓存，避免重复解析相同的metadesc字符串
_metadata_cache = {}
_metadata_lock = Lock()

class MediaCache:
    def __init__(self, capacity: int = 10):  
        self.cache = OrderedDict()
        self.capacity = capacity
        self.lock = Lock()  # 线程锁，确保线程安全
        
    def get(self, fid: str, corpid: str) -> Optional[Dict[str, Any]]:       
        with self.lock:            
            if fid in self.cache:               
                item = self.cache[fid]
                current_time = time.time()
                item['last_access'] = current_time
                self.cache.move_to_end(fid)
                return item            
            # 缓存不存在，从MySQL加载
            data = self._load_from_mysql(fid, corpid)
            if data:              
                self._add_to_cache(fid, data)
            return data
    
    def _add_to_cache(self, fid: str, data: Dict[str, Any]):
        current_time = time.time()        
        # 如果缓存已满，删除最久未使用的项（LRU策略）
        if len(self.cache) >= self.capacity:
            self.cache.popitem(last=False)        
        # 添加到缓存 - 使用简化结构，移除嵌套的'data'键
        # 创建副本并添加last_access字段
        item_data = data.copy()
        item_data['last_access'] = current_time
        self.cache[fid] = item_data
    
    def _load_from_mysql(self, fid: str, corpid: str) -> Optional[Dict[str, Any]]:       
        try:
            # 使用传入的corpid直接构建表名
            if not corpid:
                print("错误: 未提供corpid参数")
                return None
            
            table_name = f"file_info_{corpid}"
            try:
                # 查询文件信息，增加name、fsize、mtime、ftype等字段
                sql_query = f"SELECT fid, delflag, fpath, metadesc, mimeid, name, fsize, mtime, ftype FROM {table_name} WHERE fid = %s"
                result = query_mysql(sql_query, params=(fid,), fetchone=True)
                if result:
                    # 构建结果字典
                    file_info = {
                        'fid': result[0],
                        'delflag': result[1],
                        'fpath': result[2],                        
                        'metadesc': result[3],
                        'mimeid': result[4],
                        'name': result[5] if len(result) > 5 else '',
                        'fsize': result[6] if len(result) > 6 else 0,
                        'mtime': result[7] if len(result) > 7 else 0,
                        'ftype': result[8] if len(result) > 8 else 0
                    }
                    
                    # 对于音视频和图片类型，预解析metadesc
                    ftype = file_info.get('ftype', 0)
                    if ftype in [2, 4, 7]:  # 图片、音频、视频类型
                        metadesc = file_info.get('metadesc', '')
                        if metadesc:
                            # 使用缓存的元数据解析结果
                            metadata = _get_cached_metadata(metadesc)
                            file_info.update(metadata)
                    
                    return file_info
            except Exception as e:
                # 表查询失败
                print(f"查询表 {table_name} 失败: {e}")
                return None
        except Exception as e:
            print(f"从MySQL加载文件信息失败: {e}")
            return None
    
    def update(self, fid: str, data: Dict[str, Any]):        
        with self.lock:
            if fid in self.cache:
                # 更新现有缓存
                self.cache[fid].update(data)
                self.cache[fid]['last_access'] = time.time()
                self.cache.move_to_end(fid)
            else:
                # 添加新缓存
                self._add_to_cache(fid, data)
    
    def remove(self, fid: str):       
        with self.lock:
            if fid in self.cache:
                del self.cache[fid]
    
    def get_fid_mysql(self, fid: str, corpid: str) -> Optional[Dict[str, Any]]:      
        data = self._load_from_mysql(fid, corpid)
        if data:
            # 更新或添加到缓存
            self.update(fid, data)
            # 返回缓存的内容（包含last_access字段，外部调用会移除它）
            if fid in self.cache:
                return self.cache[fid]
        return data
    

# 创建全局缓存实例
media_cache = MediaCache()

# 辅助函数，用于在应用中方便地访问缓存
def get_fid_cache(fid: str, corpid: str) -> Optional[Dict[str, Any]]:   
    with media_cache.lock:
        # 检查缓存是否存在
        if fid in media_cache.cache:
            item = media_cache.cache[fid]
            delflag = item.get('delflag', 0)
            last_access = item.get('last_access', 0)
            current_time = time.time()
            
            # 需求1：当delflag为5（上传中）且last_access超过30秒时重新从MySQL加载
            if delflag == 5 and (current_time - last_access > 30):
                # 从MySQL重新加载并更新缓存
                return get_fid_from_mysql(fid, corpid)
            
            # 需求2：对于已完成上传（delflag不为5）的图片/音视频，如果metadesc为空，也重新加载
            if delflag != 5 and item.get('ftype') in [2, 4, 7] and not item.get('metadesc') and (current_time - last_access > 30):
                return get_fid_from_mysql(fid, corpid)
            
            # 更新访问时间并返回缓存的副本
            item['last_access'] = current_time
            media_cache.cache.move_to_end(fid)
            # 创建副本避免外部修改影响缓存
            result = item.copy()
            # 移除last_access字段后返回
            result.pop('last_access', None)
            return result
    
    # 缓存不存在，从get方法获取（会自动查询MySQL并缓存）
    file_info = media_cache.get(fid, corpid)
    if file_info and 'last_access' in file_info:
        # 移除last_access字段后返回
        file_info.pop('last_access', None)
    return file_info

# 辅助函数，强制从MySQL获取文件信息并更新缓存
def get_fid_from_mysql(fid: str, corpid: str) -> Optional[Dict[str, Any]]:   
    file_info = media_cache.get_fid_mysql(fid, corpid)
    if file_info and 'last_access' in file_info:
        # 移除last_access字段后返回
        file_info.pop('last_access', None)
    return file_info

# 辅助函数，获取缓存的元数据解析结果，避免重复解析
def _get_cached_metadata(metainfo: str) -> Dict[str, str]:
    """
    获取缓存的元数据解析结果，如果不存在则解析并缓存
    :param metainfo: 分号分隔的元数据字符串
    :return: 包含元数据的字典
    """
    with _metadata_lock:
        # 检查缓存中是否已存在解析结果
        if metainfo in _metadata_cache:
            return _metadata_cache[metainfo]
        
        # 解析元数据
        result = {}
        if not metainfo:
            _metadata_cache[metainfo] = result
            return result
        
        # 按分号分割字符串
        parts = metainfo.split(';')
        if not parts:
            _metadata_cache[metainfo] = result
            return result
        
        # 获取文件类型（第一个字段）
        ftype = 0
        if len(parts) >= 1 and parts[0].strip():
            try:
                ftype = int(parts[0].strip())
            except ValueError:
                ftype = 0
        
        # 根据文件类型处理不同的元数据字段
        if ftype == 2:
            # 图片类型
            if len(parts) > 1:
                result['resolvepower'] = parts[1].strip()
        
        elif ftype == 7:
            # 视频类型
            if len(parts) > 1:
                result['codetime'] = parts[1].strip()
            if len(parts) > 2:
                result['vcode'] = parts[2].strip()
            if len(parts) > 3:
                result['profile'] = parts[3].strip()
            if len(parts) > 4:
                result['resolvepower'] = parts[4].strip()
            if len(parts) > 5:
                result['vbit_rate'] = parts[5].strip()
            if len(parts) > 6:
                result['display_ratio'] = parts[6].strip()
            if len(parts) > 7:
                result['bittype'] = parts[7].strip()
            if len(parts) > 8:
                result['pix_fmt'] = parts[8].strip()
            if len(parts) > 9:
                result['b_frames'] = parts[9].strip()
            if len(parts) > 10:
                result['frame_rate'] = parts[10].strip()
            if len(parts) > 11:
                result['level'] = parts[11].strip()
            if len(parts) > 12:
                result['acode'] = parts[12].strip()
            if len(parts) > 13:
                result['sample_rate'] = parts[13].strip()
            if len(parts) > 14:
                result['abit_rate'] = parts[14].strip()
            if len(parts) > 15:
                result['channel'] = parts[15].strip()
        
        elif ftype == 4:
            # 音频类型
            if len(parts) > 1:
                result['acode'] = parts[1].strip()
            if len(parts) > 2:
                result['sample_rate'] = parts[2].strip()
            if len(parts) > 3:
                result['abit_rate'] = parts[3].strip()
            if len(parts) > 4:
                result['channel'] = parts[4].strip()
            if len(parts) > 5:
                result['codetime'] = parts[5].strip()
        
        # 缓存解析结果
        _metadata_cache[metainfo] = result
        return result

# 保持原有接口兼容性
def meta_buffer_json(metainfo: str) -> Dict[str, str]:
    """
    保持原有接口兼容性，内部使用缓存机制
    """
    return _get_cached_metadata(metainfo)

# 辅助函数，获取文件详细信息，包含解析后的元数据
def get_fileinfo(corpid: str, fid: str) -> Optional[Dict[str, Any]]:        
    file_info = get_fid_cache(fid, corpid)
    if not file_info:
        return None
    # 对于之前缓存的数据（没有预解析元数据的），进行补充解析
    ftype = file_info.get('ftype', 0)
    has_metadata = len(file_info.get('metadesc', '').strip()) > 1
    if ftype in [2, 4, 7] and not has_metadata:
        metadesc = file_info.get('metadesc', '')
        if metadesc:
            # 使用缓存的元数据解析结果
            metadata = _get_cached_metadata(metadesc)
            # 创建副本并更新，避免修改缓存中的原始数据
            result = file_info.copy()
            result.update(metadata)
            return result
    
    return file_info

